package com.hsz.control.validation.constraint;

import com.hsz.base.sensitivewords.EngineType;
import com.hsz.base.sensitivewords.SensitiveWord;
import com.hsz.base.sensitivewords.SensitiveWordEngine;
import com.hsz.base.sensitivewords.SensitiveWordEngineResult;
import com.hsz.base.sensitivewords.core.engine.DfaSensitiveWordEngine;
import com.hsz.base.sensitivewords.core.engine.IBaseSensitiveWordEngine;
import com.hsz.base.sensitivewords.core.init.DfaSensitiveWordInit;
import com.hsz.base.standard.constant.ContentType;
import com.hsz.base.util.BeanUtil;
import com.hsz.control.service.SensitiveService;
import com.hsz.control.validation.annotation.Sensitive;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * Sensitive validator
 *
 * @description: 敏感字校验注解实现
 * @author: cyj
 * @date 2020 -12-01 11:04:28
 */
@Slf4j
public class SensitiveValidator implements ConstraintValidator<Sensitive, String> {

    /**
     * errorMessage
     */
    public static final String errorMessage = "该%s文本包含敏感字{%s}, 请修改!";

    /**
     * Engine type
     */
    private EngineType engineType;

    /**
     * Rule
     */
    private IBaseSensitiveWordEngine.Rule rule;

    /**
     * Content type
     */
    private ContentType contentType;

    @Override
    public void initialize(Sensitive constraintAnnotation) {
        this.engineType = constraintAnnotation.engineType();
        this.rule = constraintAnnotation.engineRule();
        this.contentType = constraintAnnotation.contentType();
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
        if (null == value) {
            return true;
        }
        return check(value, constraintValidatorContext);
    }

    /**
     * Dfa check boolean
     *
     * @param value                      value
     * @param constraintValidatorContext constraint validator context
     * @return the boolean
     */
    private boolean check(String value, ConstraintValidatorContext constraintValidatorContext) {
        SensitiveService sensitiveService = BeanUtil.getBean(SensitiveService.class);
        if (null == sensitiveService) {
            return true;
        }
        List<SensitiveWord> sensitiveWords = sensitiveService.findAll();
        if (CollectionUtils.isEmpty(sensitiveWords)) {
            return true;
        }
        // 构造过滤器引擎
        SensitiveWordEngine sensitiveWordEngine = initEngine(sensitiveWords);
        if (null == sensitiveWordEngine) {
            return true;
        }
        // 敏感字检查
        List<SensitiveWordEngineResult> sensitiveWordEngineResults = sensitiveWordEngine.getMatchKey(value, rule);
        // 返回结果
        if (CollectionUtils.isEmpty(sensitiveWordEngineResults)) {
            return true;
        } else {
            // 串改message
            updateMessage(sensitiveWordEngineResults, constraintValidatorContext);
            return false;
        }
    }

    private SensitiveWordEngine initEngine(List<SensitiveWord> sensitiveWords) {
        // 暂时只支持DFA
        if (EngineType.DFA == engineType) {
            return new SensitiveWordEngine(DfaSensitiveWordEngine.class, DfaSensitiveWordInit.class, sensitiveWords);
        }
        return null;
    }

    /**
     * Update message *
     *
     * @param sensitiveWordEngineResults sensitive word engine results
     * @param constraintValidatorContext constraint validator context
     */
    private void updateMessage(List<SensitiveWordEngineResult> sensitiveWordEngineResults,
                               ConstraintValidatorContext constraintValidatorContext) {
        Set<String> sensitivies = sensitiveWordEngineResults.stream().
                map(sensitiveWordEngineResult -> sensitiveWordEngineResult.getMatchSensitive()).collect(Collectors.toSet());
        StringBuffer message = new StringBuffer();
        sensitivies.stream().forEach(sensitive -> message.append(sensitive + ","));
        message.delete(message.length() - 1, message.length());
        // 禁用默认异常提示信息
        constraintValidatorContext.disableDefaultConstraintViolation();
        // 串改异常提示信息
        String adviceMessage = String.format(errorMessage, contentType.message, message.toString());
        constraintValidatorContext.buildConstraintViolationWithTemplate(adviceMessage).addConstraintViolation();
    }
}
